home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gigarom 1
/
Gigarom Macintosh Archives (Quantum Leap)(CDRM1080320)(1993).iso
/
FILES
/
DEV
/
I-Z
/
MacRecorder® HackersToolkit.cpt
/
Sound.c
< prev
next >
Wrap
Text File
|
1989-12-07
|
8KB
|
335 lines
/* Copyright © 1989 Farallon Computing, Inc */
#include "Sound.h"
#define NIL 0
#define Snd2HeaderSize 36
#define K 1024 /* 1024 bytes per K */
void InitMac( void);
short Record( Handle, short);
Handle GetBigHandle( short);
long Mono22Khz( char*, Ptr, char*, long);
void BuildSoundHeader( Handle);
void FillInNumSample( Handle, long);
void Interrupts( short );
void SCCPort( short, char**, char** );
void SCCPoke( char*, short, short );
void SCCInit( char*);
void BuildFlipTable( char*);
short Flip( short);
/*
** Geneal function to initialize the managers
*/
void InitMac()
{
register short i;
Ptr p;
asm
{
MOVE.L SP,A0 ; current stack pointer to A0
SUB #0x4000,A0 ; allow it to expand 16K lower
MOVE.L A0,p
}
SetApplLimit( p );
MaxApplZone(); /* grow the Application's heap zone to its limit */
/*
** Initialize all managers through the Window Manager here,
** rather than in our initialization segment, because
** InitWindows allocates non-relocatables. We don't want
** those non-relocatables allocated above the initialization
** segment which will be loaded low by the 64K ROM segment
** loader. The remaining managers are initialized from our
** initialization segment.
*/
InitGraf( &thePort );
InitFonts();
InitWindows();
/*
Call MoreMasters here because it allocates non-relocatables.
*/
for (i=0;i<6;i++) MoreMasters();
InitMenus();
InitDialogs( NIL );
TEInit();
InitCursor(); /* arrow cursor */
}
/*
** Records a sound into the sound Handle
** Builds a header around the sound to make it a snd2 format
** If recording fails, returns recordErr ( = -1)
** Recording stops when memory runs out OR the mouse
** is clicked (or moved on MacII or more recent models)
**
** We record a mono sound at 22Khz
*/
short Record( soundHandle, whichPort)
Handle soundHandle;
short whichPort;
{
char* writePort;
char* readPort;
unsigned char table[256 + 1];
long size = GetHandleSize( soundHandle);
long len;
/* the handle is too small to even accomodate the header */
if (size < Snd2HeaderSize)
return( recordErr);
/* initialize MacRecorder */
SCCPort( whichPort, &readPort, &writePort );
SCCInit( writePort );
BuildFlipTable( (char *)table );
BuildSoundHeader( soundHandle); /* builds snd2 header */
HLock( soundHandle);
Interrupts( false ); /* turn interrupts off */
/* actually record it here */
len = Mono22Khz( readPort, (Ptr)(*soundHandle + Snd2HeaderSize),
(char *)table, size - Snd2HeaderSize );
Interrupts( true ); /* turn interrupts back on */
HUnlock( soundHandle);
if (len == -1)
{
/* could not record */
return( recordErr);
}
else
{
/* fills header with # samples */
FillInNumSample( soundHandle, len);
SetHandleSize( soundHandle, len + Snd2HeaderSize); /* shrink the handle */
return( noErr);
}
}
/*
** Allocate the largest possible handle
** while leaving the given number of K
** available
*/
Handle GetBigHandle( leaveThis)
short leaveThis;
{
long maxLength;
Handle reserveHandle;
Handle bigHandle;
reserveHandle = NewHandle( leaveThis*K);
if (reserveHandle == 0)
return( 0); /* we don't even HAVE the memory we want to reserve */
/* allocate largest possible handle now */
maxLength = CompactMem( 0x7FFFFFFFL);
bigHandle = NewHandle( maxLength);
DisposHandle( reserveHandle); /* release memory we were reserving */
return( bigHandle);
}
static void SCCInit( scc )
char *scc;
{
Interrupts( false ); /* turn off interupts */
SCCPoke(scc,9,2); /* NV only */
SCCPoke(scc,4,12); /* 2 stop bits, Async, x16 clock mode */
SCCPoke(scc,1,1); /* no Rx/Tx Int, Ext Int ON (mouse) */
SCCPoke(scc,3,193); /* initialize receiver, 8bits */
SCCPoke(scc,5,122); /* 8bits/char, send break(for other hardware!), Tx enable */
SCCPoke(scc,11,48); /* use TRxC as receiver clock */
SCCPoke(scc,14,1); /* BR enable, nothing else */
SCCPoke(scc,15,8); /* Interrupt on CD changes (mouse), turn off CTS interrupt */
SCCPoke(scc,64,64); /* Reset Rx CRC */
SCCPoke(scc,9,10); /* initialize master interrupt and NV */
Interrupts( true ); /* turn on interrupts */
}
static void SCCPoke( scc, reg, value )
char *scc;
short reg, value;
{
*scc = reg;
*scc = value;
}
static void SCCPort( whichPort, read, write )
short whichPort;
char **read, **write;
{
*read = SCCRd;
*write = SCCWr;
if (whichPort == modemPort)
{
*read += 2;
*write += 2;
}
}
/*
** Data comes out of the MacRecorder with the bits of each
** byte in the wrong order. So, we must flip each byte to
** get it in the right order. Instead of doing this on the
** fly, we build a table that has an entry for each value
** a byte can have and which gives the flip value for each
** entry
*/
static void BuildFlipTable( p )
register char *p;
{
register short i;
for (i=0; i<256; i++)
p[i] = Flip(i);
}
/* flips a byte (byte 0 becomes byte 7, etc.) */
static short Flip( x )
short x;
{
asm
{
MOVEM.L D1-D2,-(A7) ; save on stack
MOVE x,D1 ; value we want to flip
MOVEQ #7,D2 ; loop though 8 bits
MOVEQ #0,D0 ; our result
@0
ROXL.B #1,D1 ; get bit n from source
ROXR.B #1,D0 ; roll into MSB of dest
DBRA D2,@0 ; are we done?
; D0 contains flipped value
MOVEM.L (A7)+,D1-D2 ; retrieve saved registers
}
}
/*
** Record a Mono sound at 22KHz
** len = maximum length for the sound
*/
static long Mono22Khz(fromWhere, outBuff, flipTable, len )
char* fromWhere;
Ptr outBuff;
char* flipTable;
long len;
{
asm
{
MOVEM.L A2-A4/D2-D7,-(SP) ; save regs
MOVE.L fromWhere,A4 ; get SCC
MOVE.L outBuff,A3 ; get dest buffer
MOVE.L flipTable,A2 ; get trans table
MOVE.L len,D6 ; get buffer max
MOVEQ #-1,D0 ; result code - assume the worst
MOVE.L VIA,A0 ; mouse address from VIA
MOVEQ #0,D2 ; byte holder
MOVE.L D6,D1 ; save byte count
@reset
MOVE #50000,D7 ; watchdog timer
@loop
SUBQ.L #1,D7 ; decrement watchdog
BMI.S @timeOut
BTST #3,(A0) ; mouse button abort?
BEQ.S @exit
BTST #0,(A4) ; test and wait for data from SCC
BEQ.S @loop ; not yet
MOVE.B 4(A4),D2 ; get the data
MOVE.B 0(A2,D2),(A3)+ ; stuff away
SUBQ.L #1,D6
BNE.S @reset
@exit
SUB.L D6,D1 ; get actual byte count
MOVE.L D1,D0 ; and return it
@timeOut
MOVEM.L (SP)+,A2-A4/D2-D7 ; restore regs
}
}
/*
** Takes a handle and fills in the memory at the handle
** with a Snd2 resource header
*/
static void BuildSoundHeader( soundHandle)
Handle soundHandle;
{
asm
{
MOVE.L A0, -(A7) ; save regsiter
MOVE.L soundHandle, A0 ; handle to data
MOVE.L (A0),A0 ; dereference
MOVE #2,(A0) ; format 2 resource
MOVE #1,4(A0) ; 1 sound command to follow
/* first command, 8 bytes in length */
MOVE #0x8051,6(A0) ; bufferCmd, high bit on to indicate sound
; data included
MOVE #0,8(A0) ; bufferCmd param1
MOVE.L #20,10(A0) ; bufferCmd param2,
; offset to sound header
/* sampled sound header used in a soundCmd and bufferCmd */
MOVE.L #0,14(A0) ; ptr to data
; (it follows immediately)
MOVE.L #0,18(A0) ; number of samples
; (gets filled in later)
MOVE.L #0x56EE8BA3,22(A0) ; sampling rate (22kHz)
MOVE.L #0,26(A0) ; starting of sample's loop point
MOVE.L #0,30(A0) ; ending of sample's loop point
MOVE.B #0,34(A0) ; standard sample encoding
MOVE.B #0x3C,35(A0) ; base note (middle C)
MOVE.L (A7)+,A0 ; restore A0
}
/* sound should start at byte 36 */
}
static void FillInNumSample( soundHandle, numSamples)
Handle soundHandle;
long numSamples;
{
asm
{
MOVE.L A0,-(A7) ; save A0
MOVE.L soundHandle,A0 ; handle to data
MOVE.L (A0),A0 ; deref
MOVE.L numSamples,18(A0) ; fill it in
MOVE.L (A7)+,A0 ; restore A0
}
}
static void Interrupts( setEm )
short setEm;
{
asm
{
MOVE setEm(A6),D0
BNE.S @0
ORI #0x0700,SR ; off
BRA.S @1
@0
ANDI #0xF8FF,SR ; on
@1
}
}